<!DOCTYPE html></script>
<html lang="en">
  
  <head>
    <meta charset="UTF-8">
    <title>data process</title>
    <style>
      canvas{
        background: rgb(0, 0, 0);
        background-image: url("./assets/data/background-small.png");
        /* background-repeat: no-repeat; */
        background-size: 600px 600px;
      }
      .g6-tooltip {
        border: 1px solid #e2e2e2;
        border-radius: 4px;
        font-size: 12px;
        color: #545454;
        background-color: rgba(255, 255, 255, 0.9);
        padding: 10px 8px;
        box-shadow: rgb(174, 174, 174) 0px 0px 10px;
      }
    </style>
  </head>
  <body>
    <div id="mountNode"></div>
    <script src="../build/g6.js"></script>
    <script src="./assets/jquery-3.2.1.min.js"></script>
    <script>
      const colors = ['rgb(64, 174, 247)', 'rgb(108, 207, 169)', 'rgb(157, 223, 125)', 'rgb(240, 198, 74)', 'rgb(221, 158, 97)', 'rgb(141, 163, 112)', 'rgb(115, 136, 220)', 'rgb(133, 88, 219)', 'rgb(203, 135, 226)', 'rgb(227, 137, 163)'];
      // custom the node
      G6.registerNode('breath-node', {
        afterDraw(cfg, group) {
          const r = cfg.size / 2;
          console.log(cfg);
          const back1 = group.addShape('circle', {
            zIndex: -3,
            attrs: {
              x: 0,
              y: 0,
              r,
              fill: cfg.color || (cfg.style && cfg.style.fill),
              opacity: 0.6
            }
          });
          const back2 = group.addShape('circle', {
            zIndex: -2,
            attrs: {
              x: 0,
              y: 0,
              r,
              fill: cfg.color,
              // 为了显示清晰，随意设置了颜色
              opacity: 0.6
            }
          });
          const back3 = group.addShape('circle', {
            zIndex: -1,
            attrs: {
              x: 0,
              y: 0,
              r,
              fill: cfg.color,
              opacity: 0.6
            }
          });
          group.sort(); // 排序，根据zIndex 排序
          const delayBase = Math.random() * 2000;
          back1.animate({ // 逐渐放大，并消失
            r: r + 10,
            opacity: 0.0
          }, {
            repeat: true, // 循环
            duration: 3000,
            easing: 'easeCubic',
            delay: delayBase // 无延迟
          });
          back2.animate({ // 逐渐放大，并消失
            r: r + 10,
            opacity: 0.0
          }, {
            repeat: true, // 循环
            duration: 3000,
            easing: 'easeCubic',
            delay: delayBase + 1000 // 1 秒延迟
          });
          back3.animate({ // 逐渐放大，并消失
            r: r + 10,
            opacity: 0.0
          }, {
            repeat: true, // 循环
            duration: 3000,
            easing: 'easeCubic',
            delay: delayBase + 2000 // 2 秒延迟
          });
        }
      },
      'circle');
      
      // custom the edge
      G6.registerEdge('running-polyline', {
        afterDraw(cfg, group) {
          const shape = group.get('children')[0];
          const length = shape.getTotalLength();
          const startPoint = shape.getPoint(0);
          let circleCount = Math.ceil(length / 20);
          circleCount = circleCount === 0 ? 1 : circleCount;
          for (let i = 0; i < circleCount; i++) {
            const delay = Math.random() * 1000;
            const start = shape.getPoint(i / circleCount);
            const circle = group.addShape('circle', {
              attrs: {
                x: start.x,
                y: start.y,
                r: 0.8,
                fill: '#A0F3AF',
                shadowColor: '#fff',
                shadowBlur: 30,
              }
            });
            circle.animate(ratio => {
              ratio += i / circleCount;
              if (ratio > 1) {
                ratio %= 1;
              }
              const tmpPoint = shape.getPoint(ratio);
              return {
                x: tmpPoint.x,
                y: tmpPoint.y
              };
            }, {
              repeat: true,
              duration: 10 * length,
              easing: 'easeCubic',
              delay
            });
          }
        }
      },
      'polyline');
      
      const size = window.innerHeight;
      const graphSize = [size, size];
      const graph = new G6.Graph({
        container: 'mountNode',
        width: graphSize[0],
        height: graphSize[1],
        modes: {
        default:
          [{
            type:
            'edge-tooltip',
            formatText(model) {
              const text = model.class;
              return text;
            },
            shouldUpdate: e => {  
              return true;
            }
          }]
        },
        defaultNode: {
          shape: 'breath-node',
          size: 3,
          style: {
            lineWidth: 0,
            fill: 'rgb(240, 223, 83)'
          }
        },
        defaultEdge: {
          shape: 'running-polyline',
          size: 1,
          color: 'rgb(14,142,63)',
          style: {
            opacity: 0.4,
            lineAppendWidth: 3
          }
        }
      });
      $.getJSON('https://gw.alipayobjects.com/os/basement_prod/8c2353b0-99a9-4a93-a5e1-3e7df1eac64f.json', data => {  
        const nodes = data.nodes;
        const edges = data.edges;
        const classMap = new Map();
        let classId = 0;
        nodes.forEach(node => {  
          node.y = -node.y;
        });
        edges.forEach(edge => {  
          // edge cluster
          if (edge.class && classMap.get(edge.class) === undefined) {
            classMap.set(edge.class, classId);
            classId++;
          }
          const cid = classMap.get(edge.class);
          edge.color = colors[cid % colors.length];
          const controlPoints = edge.controlPoints;
      
          controlPoints.forEach(cp => {  
            cp.y = -cp.y;
          });
        });
        scaleNodesPoints(nodes, edges, graphSize);
        graph.data(data);
        graph.render();
      });
      
      function scaleNodesPoints(nodes, edges, graphSize) {
        const size = graphSize[0] < graphSize[1] ? graphSize[0] : graphSize[1];
        let minX = 99999999999999999;
        let maxX = -99999999999999999;
        let minY = 99999999999999999;
        let maxY = -99999999999999999;
        nodes.forEach(node => {  
          if (node.x > maxX) maxX = node.x;
          if (node.x < minX) minX = node.x;
          if (node.y > maxY) maxY = node.y;
          if (node.y < minY) minY = node.y;
        });
      
        edges.forEach(edge => {  
          const controlPoints = edge.controlPoints;
          controlPoints.forEach(cp => {  
            if (cp.x > maxX) maxX = cp.x;
            if (cp.x < minX) minX = cp.x;
            if (cp.y > maxY) maxY = cp.y;
            if (cp.y < minY) minY = cp.y;
          });
        });
      
        const xScale = maxX - minX;
        const yScale = maxY - minY;
        nodes.forEach(node => {  
          node.orix = node.x;
          node.oriy = node.y;
          node.x = (node.x - minX) / xScale * size;
          node.y = (node.y - minY) / yScale * size;
        });
        edges.forEach(edge => {  
          const controlPoints = edge.controlPoints;
          controlPoints.forEach(cp => {  
            cp.x = (cp.x - minX) / xScale * size;
            cp.y = (cp.y - minY) / yScale * size;
          });
        });
      }
    </script>
  </body>

</html>